package com.lzx.adx.report.controller.v3;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.openservices.aliyun.log.producer.Producer;
import com.aliyun.openservices.log.common.LogItem;
import com.lzs.adx.commmon.redis.RedisUtils;
import com.lzs.adx.commmon.utils.DateUtils;
import com.lzs.adx.commmon.utils.JsonUtils;
import com.lzs.adx.commmon.utils.Result;
import com.lzs.adx.commmon.utils.SpringContextUtils;
import com.lzx.adx.report.cache.OcpxAccountLocalCache;
import com.lzx.adx.report.cache.ProductConfigLocalCache;
import com.lzx.adx.report.constant.ProductChannelConstant;
import com.lzs.adx.commmon.constant.RedisCacheKey;
import com.lzx.adx.report.dto.OcpxAccountDTO;
import com.lzx.adx.report.dto.ProductConfigDTO;
import com.lzx.adx.report.dto.ReportDTO;
import com.lzx.adx.report.service.ReportService;
import com.lzx.adx.report.support.context.v3.CallBackV3Context;
import com.lzx.adx.report.support.context.v3.ReportV3Context;
import com.lzx.adx.report.support.strategy.v3.channel.AbstractProductReport;
import com.lzx.adx.report.support.strategy.v3.media.AbstractChannel;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Component
public class AbstractV3Controller<T> {



    public String getEventTyp(String eventType,String dspId){
        String day= DateUtils.getCurrentTime();
        if(StringUtils.isBlank(eventType)){
            eventType="click";
        }
        if(eventType.equals("click")){
            return  String.format(RedisCacheKey.OCPX_REQ_CLICK_KEY,day,dspId);
        }else{
            return  String.format(RedisCacheKey.OCPX_REQ_IMP_KEY,day,dspId);
        }
    }


    public String reportBase(T t){
        ReportService reportService = SpringContextUtils.getBean(ReportService.class);
        RedisUtils redisUtils = SpringContextUtils.getBean(RedisUtils.class);
        ReportV3Context handlerReportContext = SpringContextUtils.getBean(ReportV3Context.class);
        ThreadPoolTaskExecutor reportExecutor = (ThreadPoolTaskExecutor) SpringContextUtils.getBean("reportExecutor");

        log.info("的请求参数为{}", JsonUtils.toJsonString(t));
        //1.收到监测的数据存储
        ReportDTO reportDTO = BeanUtil.copyProperties(t, ReportDTO.class);
        reportDTO.setType(2);
        reportDTO.setEventType(StringUtils.isBlank(reportDTO.getEventType())?"click":reportDTO.getEventType());
        reportDTO.setBizRequestId(IdUtil.fastSimpleUUID()+reportDTO.getDspId());
        reportDTO.setCreateTime(new Date());
        reportDTO.setUpdateTime(new Date());
        reportDTO.setExtend(JsonUtils.toJsonString(t));
        reportDTO.setTraceTime(String.valueOf(System.currentTimeMillis()/1000));
        reportExecutor.execute(()->{
            reportService.saveData(reportDTO);

        });

        //请求数据,计数
        String key = getEventTyp(reportDTO.getEventType(), reportDTO.getDspId());
        redisUtils.incr(key,RedisCacheKey.TWO_FOUR_HOURS);


        OcpxAccountDTO accountDTO = OcpxAccountLocalCache.getInstance().get(reportDTO.getDspId());


        //不需要请求产品端的产品
        if (ProductChannelConstant.productChannelList.contains(accountDTO.getProductChannel())) {
            log.info("账户ID{},无需上报给产品", reportDTO.getDspId());
            return "success";
        }
        ProductConfigDTO productConfigDTO = ProductConfigLocalCache.getInstance().get(accountDTO.getProductChannel());

        AbstractProductReport abstractReport = handlerReportContext.getReport(accountDTO.getProductChannel());
        //正常上报模式
        if(accountDTO.getReportType().equals(2)) {

            return abstractReport.virtual(reportDTO,accountDTO);
        }
        String result = abstractReport.execute(reportDTO, accountDTO, productConfigDTO);


        return result;
    }


    public ResponseEntity baseCallback(Map<String,String> allParams) throws Exception {
        ReportService reportService = SpringContextUtils.getBean(ReportService.class);
        CallBackV3Context handlerCallBackContext = SpringContextUtils.getBean(CallBackV3Context.class);
        ThreadPoolTaskExecutor callBackExecutor = (ThreadPoolTaskExecutor) SpringContextUtils.getBean("callBackExecutor");

        String time = String.valueOf(System.currentTimeMillis());
        log.info("收到了回掉结果，请求的参数为{}",JSONObject.toJSONString(allParams));
        if (CollectionUtil.isEmpty(allParams)) {
            log.info("收到了回掉结果回调信息参数异常");
            return ResponseEntity.status(HttpStatus.BAD_REQUEST).build();
        }
        // 获取当前线程的MDC上下文
        Map<String, String> contextMap = MDC.getCopyOfContextMap();

        //2.从缓存加载配置
        callBackExecutor.execute(()->{
            // 在子线程中设置MDC上下文
            if (contextMap != null) {
                MDC.setContextMap(contextMap);
            }
            handerCallBack(allParams, reportService, handlerCallBackContext, time);
            // 清除子线程的MDC上下文
            MDC.clear();
        });

        return ResponseEntity.ok(new Result());
    }


    /**
     * 处理回掉的相关业务
     * @param allParams
     * @param reportService
     * @param handlerCallBackContext
     * @param time
     */
    private void handerCallBack(Map<String, String> allParams, ReportService reportService, CallBackV3Context handlerCallBackContext, String time) {
        String requestId = allParams.get("requestId");
        if(StringUtils.isBlank(requestId)){
            requestId= allParams.get("clickId");
        }

        //1.把转换结果更新到数据库
        Map<String, Object> params = new HashMap<>();
        params.put("bizRequestId", requestId);
        List<ReportDTO> list = reportService.list(params);
        ReportDTO reportDTO;
        if (CollectionUtil.isNotEmpty(list)) {
            reportDTO = list.get(0);
            log.info("账号{},收到了回传，回掉的结果为{}",reportDTO.getDspId(),JSONObject.toJSONString(allParams));
        } else {
            log.error("当前流水号{}，系统当前不存在",requestId);
            return;
        }

        OcpxAccountDTO accountDTO = OcpxAccountLocalCache.getInstance().get(reportDTO.getDspId());
        ProductConfigDTO productConfigDTO = ProductConfigLocalCache.getInstance().get(accountDTO.getProductChannel());
        String callCode= productConfigDTO.getCallType();
        String eventTypeResult;
        //未配置转化字段，设置默认值
        if(StringUtils.isBlank(callCode)){
            eventTypeResult=productConfigDTO.getDefaultType();
        }else{
            eventTypeResult = allParams.get(callCode);
            //如果配置了转化类型，但是值为空，看有没有设置默认值
            if(StringUtils.isBlank(eventTypeResult)){
                //账户设置了,以账户的优先级为准,否则走通用的设置
                if(StringUtils.isNotBlank(accountDTO.getDefaultKey())){
                    eventTypeResult=accountDTO.getDefaultKey();
                }else {
                    eventTypeResult = productConfigDTO.getDefaultType();
                }
            }
        }
        AbstractChannel abstractReport = handlerCallBackContext.getCallBack(accountDTO.getMediaChannel());
        abstractReport.callback(reportDTO, accountDTO, eventTypeResult, time);


    }



//    private static void sendLog(String allParams, Producer producer, LogProducerSlsConfig logProducerConfig, OcpxAccountDTO accountDTO, String result, String category) {
//        LogItem logItem = new LogItem();
//        logItem.PushBack("category", category);
//        logItem.PushBack("message", allParams);
//        logItem.PushBack("id", accountDTO.getId());
//        logItem.PushBack("responseResult", result);
//        logItem.PushBack("fullURL", accountDTO.getFinalURL());
//
//        try {
//            producer.send(
//                    logProducerConfig.getProject(),
//                    logProducerConfig.getLogstore2(),
//                    " ",
//                    " ",
//                    logItem
//            );
//        } catch (InterruptedException e) {
//            log.warn("The current thread has been interrupted during send logs.");
//        } catch (Exception e) {
//            log.error("Failed to send log, logItem={}, e=", logItem, e);
//        }
//    }

//    private static void sendReportLog2SLS(ReportDTO reportDTO, Producer producer, LogProducerSlsConfig logProducerConfig) {
//        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//        LogItem logItem = new LogItem((int) (new Date().getTime() / 1000));
//
//        logItem.PushBack("id", String.valueOf(reportDTO.getId()));
//        logItem.PushBack("dsp_id", reportDTO.getDspId());
//        logItem.PushBack("event_type", reportDTO.getEventType());
//        logItem.PushBack("trace_time", reportDTO.getTraceTime());
//        logItem.PushBack("ip", reportDTO.getIp());
//        logItem.PushBack("oaid", reportDTO.getOaid());
//        logItem.PushBack("campaign_id", reportDTO.getCampaignId());
//        logItem.PushBack("adgroup_id", reportDTO.getAdgroupId());
//        logItem.PushBack("content_id", reportDTO.getContentId());
//        logItem.PushBack("callback", reportDTO.getCallback());
//        logItem.PushBack("requestId", reportDTO.getRequestId());
//        logItem.PushBack("create_time", sdf.format(reportDTO.getCreateTime()));
//        logItem.PushBack("channel", reportDTO.getChannel());
//        logItem.PushBack("tag_id", reportDTO.getTagId());
//        logItem.PushBack("result_type", reportDTO.getResultType());
//        logItem.PushBack("result_time", reportDTO.getResultTime());
//        logItem.PushBack("biz_request_id", reportDTO.getBizRequestId());
//        logItem.PushBack("imei", reportDTO.getImei());
//        logItem.PushBack("update_time", sdf.format(reportDTO.getUpdateTime()));
//        logItem.PushBack("user_agent", reportDTO.getUser_agent());
//        logItem.PushBack("hash_android_id", reportDTO.getHash_android_id());
//        logItem.PushBack("extend", reportDTO.getExtend());
//        logItem.PushBack("day", reportDTO.getDay());
//        logItem.PushBack("day_time", reportDTO.getDayTime());
//        logItem.PushBack("imei_sum", reportDTO.getImeiSum());
//        logItem.PushBack("oaid_sum", reportDTO.getOaidSum());
//        logItem.PushBack("appkey", reportDTO.getAppkey());
//        logItem.PushBack("sid", reportDTO.getSid());
//        logItem.PushBack("unionSite", reportDTO.getUnionSite());
//        logItem.PushBack("act_id", reportDTO.getActId());
//        logItem.PushBack("os", reportDTO.getOs());
//        logItem.PushBack("idfa", reportDTO.getIdfa());
//        logItem.PushBack("idfa_sum", reportDTO.getIdfaSum());
//        logItem.PushBack("cid", reportDTO.getCaid());
//        logItem.PushBack("cid_sum", reportDTO.getCaidSum());
//        logItem.PushBack("type", String.valueOf(reportDTO.getType()));
//        logItem.PushBack("term", String.valueOf(reportDTO.getTerm()));
//
//        try {
//            producer.send(
//                    logProducerConfig.getProject(),
//                    logProducerConfig.getLogstore(),
//                    " ",
//                    " ",
//                    logItem
//            );
//        } catch (InterruptedException e) {
//            log.warn("The current thread has been interrupted during send logs.");
//        } catch (Exception e) {
//            log.error("Failed to send log, logItem={}, e=", logItem, e);
//        }
//    }
}
